package 
{

    import flash.display.Sprite;
    import br.com.stimuli.loading.BulkLoader;
    import org.libspark.flartoolkit.core.param.FLARParam;
    import org.libspark.flartoolkit.core.FLARCode;
    import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
    import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.display.Bitmap;
    import br.com.stimuli.loading.BulkProgressEvent;
    import flash.display.PixelSnapping;
    import flash.display.BitmapData;
    import org.libspark.flartoolkit.support.pv3d.FLARCamera3D;
    import org.libspark.flartoolkit.support.pv3d.FLARBaseNode;
    import org.papervision3d.render.LazyRenderEngine;
    import org.papervision3d.view.Viewport3D;
    import org.papervision3d.scenes.Scene3D;
    import flash.events.Event;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.lights.PointLight3D;
    import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.libspark.flartoolkit.detector.FLARMultiMarkerDetector;

    public class Main extends Sprite
    {
        
        private var _loader:BulkLoader;
        
        private var _flarParam:FLARParam;
        private var _code:FLARCode;
        private var _codeList:Vector.<FLARCode>;
        
        private var _raster:FLARRgbRaster_BitmapData;
        private var _detector:FLARSingleMarkerDetector;
        private var _detector2:FLARSingleMarkerDetector;
        
        private var _multiDetector:FLARMultiMarkerDetector;
        
        
        
        private var _webcam:Camera;
        private var _video:Video;
        private var _capture:Bitmap;
        
        private var _config:Array;
        
        private var _markerNode:FLARBaseNode;
        private var _base:Sprite;
        private var _viewport:Viewport3D;
        private var _camera3d:FLARCamera3D;
        private var _scene:Scene3D;
        private var _renderer:LazyRenderEngine;
        
        private var _markerTransMatResult:FLARTransMatResult = new FLARTransMatResult();
        
        private var _plane:Plane;
        private var _planeList:Vector.<Plane>;
        
        private var _cube:Cube;
        
        private var _markerNotFoundedTime:int = 0;
	
    	public function Main()
    	{
    		super();
    		
    		_initConfig();
    		    		
    		_loader = new BulkLoader('storage');
    		_loader.add(_config['camera_parameters_file'], {type: 'binary'});
    		_loader.add(_config['pattern']);
    		_loader.add('assets/common/markers/0');
    		_loader.add('assets/common/markers/1');
    		_loader.add('assets/common/markers/2');
    		_loader.addEventListener(BulkProgressEvent.COMPLETE, _doOnLoaded);
    		_loader.start();
    	}
    	
    	private function _initConfig():void
    	{
    	    _config = new Array();
    	    _config['camera_parameters_file'] = 'config/camera_para.dat';
    	    _config['pattern'] = 'assets/common/markers/hiro.pat';
    	    _config['width'] = 640;
    	    _config['height'] = 480;
    	}
    	
    	private function _initFLAR():void
    	{
    	    _flarParam = new FLARParam();
            _flarParam.loadARParam(_loader.getBinary(_config['camera_parameters_file']));            
            _flarParam.changeScreenSize(_config['width'], _config['height']);
            
            _code = new FLARCode(16, 16);
            _code.loadARPatt(_loader.getText('assets/common/markers/2'));
            /*_code.loadARPatt(_loader.getText('assets/common/markers/0'));*/
            
            _codeList = new Vector.<FLARCode>;
            
            _codeList[0] = new FLARCode(16,16);
            _codeList[0].loadARPatt(_loader.getText('assets/common/markers/0'));
            
            _codeList[1] = new FLARCode(16,16);
            _codeList[1].loadARPatt(_loader.getText('assets/common/markers/1'));
            
            _raster = new FLARRgbRaster_BitmapData(_config['width'], _config['height']);
            _capture = new Bitmap(BitmapData(_raster.getBuffer()), PixelSnapping.AUTO, true);
            _capture.width = _config['width'];
            _capture.height = _config['height'];
            
            _detector = new FLARSingleMarkerDetector(_flarParam, _codeList[0], 80);            
            _detector2 = new FLARSingleMarkerDetector(_flarParam, _codeList[1], 80);            
            
            _detector.setContinueMode(true);
            
            /*_multiDetector = new FLARMultiMarkerDetector(_flarParam, _codeList, new Vector.<Number>(80,80), 2);*/
            
            _markerNode = new FLARBaseNode();
            
    	}
    	
    	private function _initWebCamera():void
    	{
    	    _webcam = Camera.getCamera();
    	    _webcam.setMode(_config['width'], _config['height'], 30);
    	    _video = new Video(_config['width'], _config['height']);
    	    _video.attachCamera(_webcam);    	    
    	}
    	
    	private function _initPV3D():void
    	{
    	    _base = addChild(new Sprite()) as Sprite;
            _base.scaleX = -1;
            _base.x = _config['width'];
            _base.addChild(_capture);
    	    
    	    _viewport = new Viewport3D(320, 240);
    	    _viewport.scaleX = _config['width'] / 320;
    	    _viewport.scaleY = _config['height'] / 240;
    	    _viewport.x = -4; //? ;)
    	    
    	    _base.addChild(_viewport);
    	    
    	    _camera3d = new FLARCamera3D(_flarParam);
    	    _scene = new Scene3D();   	    
    	    
    	    
    	    _configureMarkerNode();
    	    
    	    _scene.addChild(_markerNode);
    	}
    	
    	private function _initRendering():void
    	{
    	    _renderer = new LazyRenderEngine(_scene, _camera3d, _viewport);
    	    addEventListener(Event.ENTER_FRAME, _render);
    	}
    	
    	private function _configureMarkerNode():void
    	{    	    
    	    var wmat:WireframeMaterial = new WireframeMaterial(0xff0000, 1, 2);
    	    _plane = new Plane(wmat, 80, 80);
    	    _plane.rotationX = 180;
    	    _markerNode.addChild(_plane);
    	    
    	    _planeList = new Vector.<Plane>();
    	    _planeList.push(new Plane(wmat, 80, 80));
    	    _planeList.push(new Plane(wmat, 80, 80));
    	    
    	    _markerNode.addChild(_planeList[0]);
    	    _markerNode.addChild(_planeList[1]);
    	    
    	    _planeList[0].rotationX = 180;
    	    _planeList[1].rotationX = 180;
    	    
            /*var light:PointLight3D = new PointLight3D();
            light.x = 0;
            light.y = 1000;
            light.z = -1000;
            
            
            var fmat:FlatShadeMaterial = new FlatShadeMaterial(light, 0xff22aa, 0x75104e); // Color is ping. / ピンク色。
            _cube = new Cube(new MaterialsList({all: fmat}), 40, 40, 40); // 40mm x 40mm x 40mm
            _cube.z = 40; // Move the cube to upper (minus Z) direction Half height of the Cube. / 立方体の高さの半分、上方向(-Z方向)に移動させるとちょうどマーカーにのっかる形になる。
            _markerNode.addChild(_cube);*/
    	}
    	
    	private function _doOnLoaded(e:BulkProgressEvent):void
    	{
    	    trace('_initFLAR');
    	    _initFLAR();
    	    trace('_initWebCamera');
    	    _initWebCamera();
    	    trace('_initPV3D');
    	    _initPV3D();
    	    trace('_initRendering');
    	    _initRendering();
    	}
    	
    	private function _render(e:Event):void
    	{
    	    _capture.bitmapData.draw(_video);
    	    
    	    var detected:Boolean = false;
    	    var detected2:Boolean = false;
    	    var multiNumber:int = 0;
    	    
    	    try {
                detected = _detector.detectMarkerLite(_raster, 80) && _detector.getConfidence() > 0.5;
                detected2 = _detector2.detectMarkerLite(_raster, 80) && _detector2.getConfidence() > 0.5;
                /*multiNumber = _multiDetector.detectMarkerLite(_raster, 80);*/
    	    } catch (e:Error) {
    	       trace(e);
    	    }
    	    
            /**/
    	    
            /*var tMatrix:FLARTransMatResult = new FLARTransMatResult();
            if (multiNumber > 0) {
                trace(multiNumber);             
                for (var i:int = 0; i < 1; i++) {
                   if (_multiDetector.getConfidence(i) > 0.5) {                    
                       _detector.getTransformMatrix(tMatrix);                      
                       _markerNode.setTransformMatrix(tMatrix);
                   }
                }
            }*/
    	    
            if (detected) {
                trace(detected2);
                _detector.getTransformMatrix(_markerTransMatResult);
                _markerNode.setTransformMatrix(_markerTransMatResult);
                _markerNotFoundedTime = 0;
                _markerNode.visible = true;
            } else {                
                _markerNotFoundedTime++;
                _markerNode.visible = _markerNotFoundedTime < 5;
            }
    	    
    	    
    	    _renderer.render();
    	}
	
    }

}